﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using SFP.Audio;
using SFP.Input;

namespace SFP
{
    /* The Game class describes a specific structure for handling a render loop of a graphics application.
     * Thus the extending class has to implement the methods Initialize, LoadContent and UnloadContent which
     * which will be called once aswell as the methods draw and update which will be called permanently
     * during the render loop.
     * */
    public abstract class Game
    {
        // The form of the graphics application.
        private Form form;

        // Specifies the color of the background on which the game scene is rendered on.
        public Color bgColor = Color.CornflowerBlue;
        // Specifies the internal resolution which is used for rendering.
        public readonly Size resolution;
        // Shows the amount of frames per second that are currently rendered.
        public bool showFPS;
        // Limits the frame rate to the specified frames per second (see field: maxFrameRate).
        public bool limitFrameRate;
        // Specifies the maximum of frames that are rendered per second.
        public float maxFrameRate = 60;
        // If set to 'true' the game loop will be paused if the form is inactive.
        public bool pauseGameOnInactiveForm = true;
        // Prohibits the form from closing
        public bool forbidClosing = false;

        /* Within the constructor the startup path of the ContentLoader is set to the applications startup path.
         * So every path that is given to the ContentLoader will be relative to the applications EXE file.
         * */
        public Game(Size resolution)
        {
            this.resolution = resolution;
            ContentLoader.startupPath = Application.StartupPath + "\\";
            form = new SFPForm(this);
            Keyboard.form = form;
        }

        /* Starts the graphics application by calling methods for initial things and running the private form.
         * */
        public void Run()
        {
            Run(false);
        }

        public void Run(bool runAsSubForm)
        {
            Initialize();
            LoadContent();

            if (runAsSubForm)
            {
                form.Show();
            }
            else
            {
                try
                {
                    Application.Run(form);
                }
                catch (ObjectDisposedException e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }

        /* Returns the private form of the graphics application.
         * */
        public Form GetForm()
        {
            return form;
        }

        /* Closes the form and thus quits the graphics application.
         * */
        public void Exit()
        {
            form.Close();
        }

        /* Will be called when the Form is closed to stop audio output and free resources.
         * */
        internal void FormClosingTasks()
        {
            AudioPlayer.stopAll();
            UnloadContent();
        }

        /* Calls the 'Draw' method of the implementing class. All draw operations will bei called within
         * that method. For that the 'Graphics'-object of the form is passed.
         * */
        internal void DrawGame(Graphics graphics)
        {
            Draw(graphics);
        }

        /* Calls the 'Update' method of the implementing class.
         * */
        internal void UpdateGame(double time)
        {
            Update(time);
        }

        // The following methods are called once before or after the render loop. //
        
        /* Initial operations are called in here, for example global object initializations.
         * */
        protected abstract void Initialize();
        
        /* This method is used for loading ressources like image or audio data.
         * */
        protected abstract void LoadContent();
        
        /* This method is used for unloading ressources.
         * */
        protected abstract void UnloadContent();
        
        // The following methods are permanently called within the render loop. //

        /* Within this method game specific values are updated.
         * */
        protected abstract void Update(double time);

        /* Within this method every render operation is called.
         * */
        protected abstract void Draw(Graphics graphics);
    }
}
